<?php

namespace System\Core;

/**
 * @property System\Core\Loader $Loader
 */
class Engineer extends \System\Types\Object
{

    /**
     * @var array
     */
    private static $stati = array(
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative Information',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        307 => 'Temporary Redirect',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Timeout',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Request Entity Too Large',
        414 => 'Request-URI Too Long',
        415 => 'Unsupported Media Type',
        416 => 'Requested Range Not Satisfiable',
        417 => 'Expectation Failed',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway',
        503 => 'Service Unavailable',
        504 => 'Gateway Timeout',
        505 => 'HTTP Version Not Supported'
    );

    /**
     * @var \System\Core\Errors\Error
     */
    protected $error;

    /**
     * @var \System\Core\Loader
     */
    protected $loader;

    /**
     * @var \System\Core\Benchmark
     */
    protected $benchmark;

    /**
     * @var \System\Lib\Log
     */
    protected $log;

    /**
     * @var \System\Core\Output
     */
    protected $output;

    /**
     * @var \System\Core\URI
     */
    protected $uri;

    /**
     * @var \System\Core\Router
     */
    protected $router;

    /**
     * @var \System\Core\ILanguage
     */
    protected $lang;

    function __construct()
    {
        parent::__construct();

        $this->loader = Loader::GetInstance();
        $this->benchmark = Benchmark::GetInstance();
        $this->error = new Errors\Error($this);
        $this->log = \System\Lib\Log::GetInstance();
        $this->output = Output::GetInstance();
        $this->uri = URI::GetInstance();
        $this->router = Router::GetInstance();
        $lang = new \System\Core\Language();
        $this->lang = $lang->Load(null);
    }

    /**
     * @return \System\Core\Engineer
     */
    public static function &SystemEngine()
    {
        @\ini_set('magic_quotes_runtime', 0);

        if (\function_exists("\set_time_limit") == true && @\ini_get("safe_mode") == 0)
        {
            @\set_time_limit(300);
        }

        $eng = new Engineer();

        return $eng->start();
    }

    /**
     * @return \System\Core\Engineer
     */
    private function &start()
    {
        $this->benchmark->Mark('total_execution_time_start');
        $this->benchmark->Mark('loading_time:_base_classes_start');

        Hook::HookProccess(Hook::PRE_SYSTEM);

        $this->output = Output::GetInstance();

        if (Hook::HookProccess(Hook::CACHE_OVERRIDE) === false)
        {
            if ($this->output->DisplayCache($this->uri))
                exit;
        }

        $this->benchmark->Mark('loading_time:_base_classes_end');

        $class = $this->router->FetchClass();

        $method = $this->router->FetchMethod();

        $c_e = !\class_exists($class);
        $cmp = \strncmp($method, '_', 1) == 0;
        $gcm = \is_array(\get_class_methods('CI_Controller')) ?
                \get_class_methods('CI_Controller') : array();
        $map = \array_map(function($str)
                {
                    return \strtolower($str);
                }, $gcm);
        $in_a = \in_array(\strtolower($method), $map);

        if ($c_e || $cmp || $in_a)
        {
            Errors\Error::Show404Error("{$class}/{$method}");
        }

        Hook::HookProccess(Hook::PRE_CONTROLLER);

        $this->benchmark->Mark("controller_execution_time_( {$class} / {$method} )_start");

        $controller = new $class();

        Hook::HookProccess(Hook::POST_CONTROLLER_CONSTRUCTOR);

        $viewContent = null;

        // Is there a "remap" function? If so, we call it instead
        if (\method_exists($controller, '_remap'))
        {
            $viewContent = $controller->_remap($method, \array_slice($this->uri->RSegments, 2));
        }
        else
        {
            // is_callable() returns TRUE on some versions of PHP 5 for private and protected
            // methods, so we'll use this workaround for consistent behavior
            if (!\in_array($method, \get_class_methods($controller)))
            {
                // Check and see if we are using a 404 override and use it.
                if (!empty($this->router->routes['404_override']))
                {
                    $x = \explode('/', $this->router->routes['404_override']);
                    $class = $x[0];
                    $method = (isset($x[1]) ? $x[1] : 'index');
                    if (!\class_exists($class))
                    {
                        Errors\Error::Show404Error("{$class}/{$method}");
                    }

                    $cont = new \ReflectionClass($class);

                    $controller = $cont->newInstanceArgs(array());
                }
                else
                {
                    Errors\Error::Show404Error("{$class}/{$method}");
                }
            }

            // Call the requested method.
            // Any URI segments present (besides the class/function) will be passed to the method for convenience
            $viewContent = \call_user_func_array(array(&$controller, $method), \array_slice($this->uri->rsegments, 2));
        }

        $this->benchmark->Mark("controller_execution_time_( {$class} / {$method} )_end");

        Hook::HookProccess(Hook::POST_CONTROLLER);

        if (Hook::HookProccess(Hook::DISPLAY_OVERRIDE) === false)
        {
            $controller->render($viewContent);
        }

        Hook::HookProccess(Hook::POST_SYSTEM);

        //TODO - Criar Database Driver
        //DB::Close();

        return $this;
    }

    /**
     * Set HTTP Status Header
     *
     * @access	public
     * @param	int		the status code
     * @param	string
     * @return	void
     */
    public static function SetStatusHeader($code = 200, $text = '')
    {
        if ($code == '' || !\is_numeric($code))
        {
            $this->error->ShowError('Status codes must be numeric', 500);
        }

        if (isset(self::$stati[$code]) && $text == '')
        {
            $text = self::$stati[$code];
        }

        if ($text == '')
        {
            $this->error->ShowError('No status text available.  Please check your status code number or supply your own message text.', 500);
        }

        $server_protocol = (isset($_SERVER['SERVER_PROTOCOL'])) ? $_SERVER['SERVER_PROTOCOL'] : false;

        if (\substr(\php_sapi_name(), 0, 3) == 'cgi')
        {
            \header("Status: {$code} {$text}", true);
        }
        elseif ($server_protocol == 'HTTP/1.1' || $server_protocol == 'HTTP/1.0')
        {
            \header($server_protocol . " {$code} {$text}", true, $code);
        }
        else
        {
            \header("HTTP/1.1 {$code} {$text}", true, $code);
        }
    }

}
